/* component */
import BizChatBarHeader from "@src/component/business/BizChatBar/header"
import BizChatBarContent from "@src/component/business/BizChatBar/content"
/* const */
import { STREAM_BUSINESS_SOURCE_DOCUMENTS } from "@src/component/business/BizChatPanel/chat/model/const"
/* enum */
import { DEFAULT_IM_CHAT_SYSTEM_MESSAGE } from "@src/component/business/BizChatBar/model"
import { ChatSourceDocumentTypeEnum, OpenAIMessageRoleEnum } from "@src/component/business/BizChatPanel/chat/model/enum"
/* vue */
import { defineComponent } from "vue"
/* types */
import { OpenAIMessageItemType } from "@src/component/business/BizChatPanel/chat/model/type"
/* model */
import { ChatBaseParams, ChatConversationParams } from "@model/param/in/AI"
/* utils */
import { isFalsy } from "pub-bbx-utils"
import { isJSONObject } from "@src/util/lang/object"
/* hooks */
import { useTenantId, useRootUser } from '@hooks/useRootWindow'
import { useEnv } from "@hooks/useEnv"
/* scss */
import "@src/component/business/BizChatBar/index.scss"

type BizChatBarContentComponent = InstanceType<typeof BizChatBarContent>
type BizChatBarHeaderComponent = InstanceType<typeof BizChatBarHeader>

enum BizChatBarEventEnum {
  RETRY = 'retry',
  STOP = 'stop',
  CLOSE = 'close',
  USE = 'use',
  SEND = 'send',
  LOADING = 'loading',
  INPUT = 'input'
}

export default defineComponent({
  name: "biz-chat-bar",
  components: {
    BizChatBarHeader
  },
  props: {
    onDrop: {
      type: Function,
    },
    onRetry: {
      type: Function,
    },
    onStop: {
      type: Function,
    },
    onClose: {
      type: Function,
    },
    onLoading: {
      type: Function,
    }
  },
  setup() {
    
    const { isDev } = useEnv()
    const tenantId = useTenantId()
    const loginUser = useRootUser()
    
    return {
      tenantId,
      loginUser,
      isDev
    }

  },
  data() {
    return {
      robotId: null as string | number | null,
      robotAppId: null as string | number | null,
      messages: [] as OpenAIMessageItemType[],
      loading: false as boolean,
      conversationId: null as string | number | null,
      imMessageId: null as string | number | null,
      content: '' as string,
      controller: null as AbortController | null,
      resizeObserver: null as ResizeObserver | null,
      scrollIntervalIds: [] as number[]
    }
  },
  computed: {
    userId(): string {
      return this.loginUser.userId as string
    },
    bizChatBarComponent(): BizChatBarContentComponent {
      return this.$refs.BizChatBarContent as BizChatBarContentComponent
    },
    bizChatBarHeaderComponent(): BizChatBarHeaderComponent {
      return this.$refs.BizChatBarHeader as BizChatBarHeaderComponent
    }
  },
  beforeDestroy() {
    this.clearScrollInterval()
  },
  methods: {
    renderLeft() {

    },
    renderLogo() {

    },
    show(
      robotId: string | number, 
      robotAppId: string | number, 
      messages: OpenAIMessageItemType[], 
      conversationId: string | number,
      imMessageId: string
    ) {
      
      this.robotId = robotId
      this.robotAppId = robotAppId
      this.messages = messages
      this.conversationId = conversationId
      this.imMessageId = imMessageId
      this.content = ''
      this.scrollIntervalIds = []
      
      this.onAIAnswerHandler()
      // this.scrollViewHandler()
      this.emitLoadingHandler()
    },
    /**
     * @description 获取聊天基础参数
     */
    getChatBaseParams(): ChatBaseParams {
      let params = {
        tenantId: this.tenantId,
        userId: this.userId,
        conversationId: this.conversationId as string,
        businessId: this.conversationId as string,
        imMessageId: this.imMessageId as string,
        type: ChatSourceDocumentTypeEnum.IM,
        robotId: this.robotId as string,
        appId: this.robotAppId as string,
        isExternal: true,
        stream: true
      }
      
      // if (this.isDev) {
      //   params = {
      //     ...params,
      //     tenantId: '85c4d9182a09b612adb57957ffeb736f',
      //     userId: 'ee33bf10-d659-11ec-9d05-00163e304a25',
      //   }
      // } 
      
      return params
    },
    getMessages() {
      
      let newContextMessages = this.messages.map(message => {
        return {
          content: message.content,
          type: message.role
        }
      })
      
      newContextMessages.unshift({
        content: DEFAULT_IM_CHAT_SYSTEM_MESSAGE,
        type: OpenAIMessageRoleEnum.System
      })
      
      return newContextMessages
    },
    /** 
     * @description AI 回答处理
    */
    onAIAnswerHandler() {
      
      this.content = ''
      this.loading = true
      
      const baseParams: ChatBaseParams = this.getChatBaseParams()
      const params: ChatConversationParams = {
        ...baseParams,
        messages: this.getMessages()
      }
      
      try {
        this.sendMessageWithStream(params)
      } catch (error) {
        console.error(error)
      }
      
    },
    async sendMessageWithStream(params: ChatConversationParams) {
      const controller = new AbortController();
      
      this.controller = controller
      
      const url = this.isDev ? '/serve/language/chat/conversation' : '/language/chat/conversation'
      const response = await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        signal: controller.signal,
        body: JSON.stringify(params),
      });
      
      if (!response.ok) {
        return;
      }
      
      const data = response.body;
      
      if (!data) {
        return;
      }
      
      const reader = data.getReader();
      const decoder = new TextDecoder();
      let done = false;
      let text = '';
      
      while (!done) {
        
        const { value, done: doneReading } = await reader.read();
        
        done = doneReading;
        
        let chunkValue = decoder.decode(value);
        
        const dataPrefix = 'data:';
        chunkValue = chunkValue.startsWith(dataPrefix) ? chunkValue.slice(dataPrefix.length) : chunkValue;
        chunkValue = chunkValue.trim();
        
        try {
          chunkValue = chunkValue.replaceAll(dataPrefix, '');
        } catch (error) {
          chunkValue = chunkValue.replace(new RegExp(dataPrefix, 'g'), '');
        }
        
        // 如果是业务数据来源，则单独处理
        if (
          chunkValue.startsWith(STREAM_BUSINESS_SOURCE_DOCUMENTS)
        ) {
          break;
        }   
        // 如果是业务数据来源，单独处理
        else if (chunkValue.includes(STREAM_BUSINESS_SOURCE_DOCUMENTS)) {
          try {
            const index = chunkValue.indexOf(STREAM_BUSINESS_SOURCE_DOCUMENTS)
            text += chunkValue.slice(0, index)
          } catch (error) {
            console.error(error)
          }
        } 
        else {
          text += chunkValue;
        }
        
        this.content = text;
        
        this.$emit(BizChatBarEventEnum.INPUT, this.content)
        
      }
      
      try {
        if (isJSONObject(text)) {
          const result = JSON.parse(text)
          const content = result?.data?.content || ''
          this.content = content
        }
      } catch (error) {
        console.error(error)
      }
      
      this.$emit(BizChatBarEventEnum.INPUT, this.content)
      
      this.loading = false
      
      // this.$nextTick(() => {
      //   this.scrollViewContentHandler()
      // })
      
      setTimeout(() => {
        this.clearScrollInterval()
      }, 500)
      
      if (isFalsy(text)) {
        this.$message.error('网络异常，请重试')
        return
      }
      
    },
    scrollViewOnceHandler() {
      this.$nextTick(() => {
        this.scrollViewHandlerImpl()
      })
    },
    scrollViewHandler() {
      
      this.scrollViewOnceHandler()
      
      const scrollIntervalId = setInterval(() => {
        this.scrollViewContentHandler()
      }, 200)
      
      console.log('setInterval scrollViewHandler ', scrollIntervalId)
      
      this.scrollIntervalIds = [
        ...this.scrollIntervalIds,
        scrollIntervalId
      ]
      
      console.log('scrollIntervalIds ', this.scrollIntervalIds)
      
    },
    scrollViewContentHandler() {
      this.bizChatBarComponent?.$el.scrollIntoView()
      console.log('setInterval scrollViewContentHandler')
    },
    scrollViewHandlerImpl() {
      // this.bizChatBarHeaderComponent?.$el.scrollIntoView()
    },
    emitLoadingHandler() {
      setTimeout(() => {
        this.$emit(BizChatBarEventEnum.LOADING)
      }, 100)
    },
    clearScrollInterval() {
      try {
        this.scrollIntervalIds.forEach(id => {
          clearInterval(id as number)
        })
      } catch (error) {
        console.error(error)
      }
    },
    outsideClearScrollInterval() {
      this.clearScrollInterval()
    },
    onRetryHandler() {
      this.onAIAnswerHandler()
    },
    onStopHandler() {
      this.onCloseHandler()
      if (this.controller) {
        this.controller.abort()
      }
    },
    onCloseHandler() {
      this.$emit(BizChatBarEventEnum.CLOSE)
      this.clearScrollInterval()
    },
    onUseHandler() {
      this.$emit(BizChatBarEventEnum.USE, this.content)
      this.onCloseHandler()
    },
    onSendHandler() {
      this.$emit(BizChatBarEventEnum.SEND, this.content)
      this.onCloseHandler()
    },
    outsideOnStopHandler() {
      this.onStopHandler()
    }
  },
  render() {
    return (
      <div class="biz-chat-bar">
        <BizChatBarHeader
          ref="BizChatBarHeader"
          isAnswering={this.loading}
          onDrop={this.onCloseHandler}
          onRetry={this.onRetryHandler}
          onStop={this.onStopHandler}
          onUse={this.onUseHandler}
          onSend={this.onSendHandler}
        >
        </BizChatBarHeader>
        <BizChatBarContent
          ref="BizChatBarContent"
          value={this.content}
        >
        </BizChatBarContent>
      </div>
    )
  }
})